/* "$Id: utf8Wrap.c 9994 2013-09-25 21:09:00Z greg.ercolano $"
 *
 * Author: Jean-Marc Lienher ( http://oksid.ch )
 * Copyright 2000-2003 by O'ksi'D.
 *
 * This library is free software. Distribution and use rights are outlined in
 * the file "COPYING" which should have been included with this file.  If this
 * file is missing or damaged, see the license at:
 *
 *     http://www.fltk.org/COPYING.php
 *
 * Please report all bugs and problems on the following page:
 *
 *     http://www.fltk.org/str.php
 */

/*
 * X11 UTF-8 text drawing functions.
 */
#if !defined(WIN32) && !defined(__APPLE__)

#include "Xutf8.h"

#if __FLTK_LINUX__
#include <X11/Xlib.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/* External auto generated functions : */
#include "ucs2fontmap.c"
/*
 * extern int ucs2fontmap(char *s, unsigned int ucs, int enc);
 * extern int encoding_number(const char *enc);
 * extern const char *encoding_name(int num);
 */

/* The ARM header files have a bug by not taking into account that ARM cpu
 * likes pacing to 4 bytes. This little trick defines our own version of
 * XChar2b which does not have this problem
 */

#if defined(__GNUC__) && defined(__arm__) && !defined(__ARM_EABI__)
typedef struct {
	unsigned char byte1;
	unsigned char byte2;
}
__attribute__ ((packed))
Fl_XChar2b;
#else
#define Fl_XChar2b XChar2b
#endif


/*********************************************************************/
/** extract a list of font from the base font name list             **/
/*********************************************************************/
static int
get_font_list(
        const char	*base_font_name_list,
        char 		***flist)
{
	const char *ptr;
	const char *p;
	int nb;
	int nb_name;

	ptr = base_font_name_list;
	p = NULL;
	nb = 0;
	nb_name = 1;

	while (*ptr) {
		if (*ptr == ',') nb_name++;
		ptr++;
	}

	*flist = (char **) malloc(sizeof(char*) * nb_name);
	ptr = base_font_name_list;

	while (*ptr) {
		int l = 0, i = 0;

		while(isspace((int)(unsigned char)*ptr)) ptr++;
		p = ptr;
		while (*ptr && *ptr != ',') {
			ptr++;
			l++;
		}
		if (l > 2) {
			(*flist)[nb] = (char*) malloc((unsigned)l + 2);
			while (p != ptr) {
				((*flist)[nb])[i] = *p;
				i++;
				p++;
			}
			(*flist)[nb][i] = '\0';
			nb++;
		}
		if (*ptr) ptr++;
	}
	if (nb < 1) {
		free(*flist);
		*flist = (char**)NULL;
	}
	return nb;
}

/*********************************************************************/
/** get the font name used as encoding for "fontspecific" encoding  **/
/** (mainly used for adobe-symbol and adobe-zapfdingbats)	    **/
/*********************************************************************/
static int
font_spec_enc(char *font)
{
	int ret;
	char *enc;
	char *end;

	enc = font;
	while (*enc != '-') enc++;
	enc++;
	while (*enc != '-') enc++;
	enc++;
	end = enc;
	while (*end != '-') end++;
	*end = '\0';

	ret = encoding_number(enc);
	*end = '-';

	return ret;
}


/*********************************************************************/
/** get the sub range of a iso10646-1 font			    **/
/*********************************************************************/
static void
get_range(const char	*enc,
          int 		*min,
          int		*max)
{

	const char *ptr = enc;
	const char *ptr1;

	if (!enc) return;

	while (*ptr && *ptr != '-') ptr++;
	if (!*ptr) return;
	while (*ptr && *ptr != '[') ptr++;
	if (!*ptr) return;
	*min = 0xFFFF;
	*max = 0;
	while (*ptr && *ptr != ']') {
		int val;
		ptr++;
		ptr1 = ptr;
		while (*ptr && *ptr != ']' && *ptr != ' ' && *ptr != '_') ptr++;
		val = strtol(ptr1, NULL, 0);
		if (val < *min) *min = val;
		if (val > *max) *max = val;
	}
}

/*********************************************************************/
/** get the internal encoding number of each fonts 		    **/
/*********************************************************************/
static int *
get_encodings(char	**font_name_list,
              int 	*ranges,
              int 	nb_font)
{

	int *font_encoding_list;
	int i;
	i = 0;

	font_encoding_list = (int *) malloc(sizeof(int) * nb_font);
	while (i < nb_font) {
		char *ptr;
		int ec;
		ptr = font_name_list[i];
		ec = 0;
		font_encoding_list[i] = -1;
		ranges[i * 2] = 0;
		ranges[i * 2 + 1] = 0xFFFF;

		if (ptr && strstr(ptr, "fontspecific")) {
			font_encoding_list[i] = font_spec_enc(ptr);
			ptr = NULL;
		}
		while (ptr && *ptr) {
			if (*ptr == '-') {
				ec++;
				if (ec == 13) {
					font_encoding_list[i] = encoding_number(ptr + 1);
					if (font_encoding_list[i] == 0) {
						get_range(ptr + 1,
						          ranges + i * 2,
						          ranges + i * 2 + 1);
					}
					break;
				}
			}
			ptr++;
		}
		if (font_encoding_list[i] < 0) font_encoding_list[i] = 1;
		i++;
	}
	return font_encoding_list;
}

/*********************************************************************/
/** find the first font which matches the name and load it.	    **/
/*********************************************************************/
static XFontStruct *
find_best_font(Display  *dpy,
               char     **name)
{

	char **list;
	int cnt;
	XFontStruct *s;

	list = XListFonts(dpy, *name, 1, &cnt);
	if (cnt && list) {
		free(*name);
		*name = strdup(list[0]);
		s = XLoadQueryFont(dpy, *name);
		XFreeFontNames(list);
		return s;
	}
	return NULL;
}

/*********************************************************************/
/** load all fonts 						    **/
/*********************************************************************/
static void
load_fonts(Display 	   *dpy,
           XUtf8FontStruct *font_set)
{

	int i = 0;

	font_set->fonts = (XFontStruct**) malloc(sizeof(XFontStruct*) *
	                  font_set->nb_font);

	font_set->ranges = (int*) malloc(sizeof(int) *
	                                 font_set->nb_font * 2);

	font_set->descent = 0;
	font_set->ascent = 0;
	font_set->fid = 0;

	while (i < font_set->nb_font) {
		XFontStruct *fnt;

		fnt = font_set->fonts[i] =
		              find_best_font(dpy, &(font_set->font_name_list[i]));
		if (fnt) {
			font_set->fid = fnt->fid;
			if (fnt->ascent > font_set->ascent) {
				font_set->ascent = fnt->ascent;
			}
			if (fnt->descent > font_set->descent) {
				font_set->descent = fnt->descent;
			}
		} else {
			free(font_set->font_name_list[i]);
			font_set->font_name_list[i] = NULL;
		}
		i++;
	}

	font_set->encodings =
	        get_encodings(font_set->font_name_list,
	                      font_set->ranges, font_set->nb_font);

	/* unload fonts with same encoding */
	for (i = 0; i < font_set->nb_font; i++) {
		if (font_set->font_name_list[i]) {
			int j;
			for (j = 0; j < i; j++) {
				if (font_set->font_name_list[j] &&
				    font_set->encodings[j] ==
				    font_set->encodings[i] &&
				    font_set->ranges[2*j] ==
				    font_set->ranges[2*i] &&
				    font_set->ranges[(2*j)+1] &&
				    font_set->ranges[(2*i)+1]) {
					XFreeFont(dpy, font_set->fonts[i]);
					free(font_set->font_name_list[i]);
					font_set->font_name_list[i] = NULL;
					font_set->fonts[i] = 0;
				}
			}
		}
	}
}

/*********************************************************************/
/** Creates an array of XFontStruct acording to the comma separated **/
/** list of fonts. XLoad all fonts.				    **/
/*********************************************************************/
XUtf8FontStruct *
XCreateUtf8FontStruct(Display    *dpy,
                      const char *base_font_name_list)
{

	XUtf8FontStruct *font_set;

	font_set = (XUtf8FontStruct*)malloc(sizeof(XUtf8FontStruct));

	if (!font_set) {
		return NULL;
	}

	font_set->nb_font = get_font_list(base_font_name_list,
	                                  &font_set->font_name_list);

	if (font_set->nb_font < 1) {
		free(font_set);
		return NULL;
	}

	load_fonts(dpy, font_set);

	return font_set;
}


/*****************************************************************************/
/** draw a Right To Left UTF-8 string using multiple fonts as needed.	    **/
/*****************************************************************************/
void
XUtf8DrawRtlString(Display 		*display,
                   Drawable 		d,
                   XUtf8FontStruct 	*font_set,
                   GC 			gc,
                   int 			x,
                   int 			y,
                   const char		*string,
                   int 			num_bytes)
{

	int 		*encodings;	/* encodings array */
	XFontStruct 	**fonts;	/* fonts array */
	Fl_XChar2b 	buf[128];	/* drawing buffer */
	Fl_XChar2b	*ptr;		/* pointer to the drawing buffer */
	int 		fnum;		/* index of the current font in the fonts array*/
	int 		i;		/* current byte in the XChar2b buffer */
	int 		first;		/* first valid font index */
	int 		last_fnum;	/* font index of the previous char */
	int 		nb_font;	/* quantity of fonts in the font array */
	char 		glyph[2];	/* byte1 and byte2 value of the UTF-8 char */
	int		*ranges;	/* sub range of iso10646 */

	nb_font = font_set->nb_font;

	if (nb_font < 1) {
		/* there is no font in the font_set :-( */
		return;
	}

	ranges = font_set->ranges;
	fonts = font_set->fonts;
	encodings = font_set->encodings;
	i = 0;
	fnum = 0;
	ptr = buf + 128;

	while(fnum < nb_font && !fonts[fnum]) fnum++;
	if (fnum >= nb_font) {
		/* there is no valid font for the X server */
		return;
	}

	first = fnum;
	last_fnum = fnum;

	while (num_bytes > 0) {
		int 	 ulen;   /* byte length of the UTF-8 char */
		unsigned int ucs;    /* Unicode value of the UTF-8 char */
		unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */

		if (i > 120) {
			/*** draw the buffer **/
			XSetFont(display, gc, fonts[fnum]->fid);
			x -= XTextWidth16(fonts[fnum], ptr, i);
			XDrawString16(display, d, gc, x, y, ptr, i);
			i = 0;
			ptr = buf + 128;
		}

		ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs);

		if (ulen < 1) ulen = 1;

		no_spc = XUtf8IsNonSpacing(ucs);
		if (no_spc) ucs = no_spc;

		/*
		 * find the first encoding which can be used to
		 * draw the glyph
		 */
		fnum = first;
		while (fnum < nb_font) {
			if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
				if (encodings[fnum] != 0 ||
				    ((int)ucs >= ranges[fnum * 2] && (int)ucs <= ranges[fnum * 2 + 1])) {
					break;
				}
			}
			fnum++;
		}
		if (fnum == nb_font) {
			/* the char is not valid in all encodings ->
			 * draw it using the first font :-(
			 */
			fnum = first;
			ucs2fontmap(glyph, '?', encodings[fnum]);
		}

		if (last_fnum != fnum || no_spc) {
			XSetFont(display, gc, fonts[last_fnum]->fid);
			x -= XTextWidth16(fonts[last_fnum], ptr, i);
			XDrawString16(display, d, gc, x, y, ptr, i);
			i = 0;
			ptr = buf + 127;
			(*ptr).byte1 = glyph[0];
			(*ptr).byte2 = glyph[1];
			if (no_spc) {
				x += XTextWidth16(fonts[fnum], ptr, 1);
			}
		} else {
			ptr--;
			(*ptr).byte1 = glyph[0];
			(*ptr).byte2 = glyph[1];
		}
		last_fnum = fnum;
		i++;
		string += ulen;
		num_bytes -= ulen;
	}

	if (i < 1) return;

	XSetFont(display, gc, fonts[fnum]->fid);
	x -= XTextWidth16(fonts[last_fnum], ptr, i);
	XDrawString16(display, d, gc, x, y, ptr, i);
}


/*****************************************************************************/
/** draw an UTF-8 string using multiple fonts as needed.		    **/
/*****************************************************************************/
void
XUtf8DrawString(Display 	*display,
                Drawable 	d,
                XUtf8FontStruct *font_set,
                GC 		gc,
                int 		x,
                int 		y,
                const char	*string,
                int 		num_bytes)
{

	int 		*encodings; /* encodings array */
	XFontStruct 	**fonts;    /* fonts array */
	Fl_XChar2b 	buf[128];   /* drawing buffer */
	int 		fnum;       /* index of the current font in the fonts array*/
	int 		i;          /* current byte in the XChar2b buffer */
	int 		first;      /* first valid font index */
	int 		last_fnum;  /* font index of the previous char */
	int 		nb_font;    /* quantity of fonts in the font array */
	char 		glyph[2];   /* byte1 and byte2 value of the UTF-8 char */
	int		*ranges;    /* sub range of iso10646 */

	nb_font = font_set->nb_font;

	if (nb_font < 1) {
		/* there is no font in the font_set :-( */
		return;
	}
	ranges = font_set->ranges;
	fonts = font_set->fonts;
	encodings = font_set->encodings;
	i = 0;
	fnum = 0;

	while(fnum < nb_font && !fonts[fnum]) fnum++;
	if (fnum >= nb_font) {
		/* there is no valid font for the X server */
		return;
	}

	first = fnum;
	last_fnum = fnum;

	while (num_bytes > 0) {
		int 	 ulen;   /* byte length of the UTF-8 char */
		unsigned int ucs;    /* Unicode value of the UTF-8 char */
		unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */

		if (i > 120) {
			/*** draw the buffer **/
			XSetFont(display, gc, fonts[fnum]->fid);
			XDrawString16(display, d, gc, x, y, buf, i);
			x += XTextWidth16(fonts[fnum], buf, i);
			i = 0;
		}

		ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs);

		if (ulen < 1) ulen = 1;

		no_spc = XUtf8IsNonSpacing(ucs);
		if (no_spc) ucs = no_spc;

		/*
		 * find the first encoding which can be used to
		 * draw the glyph
		 */
		fnum = first;
		while (fnum < nb_font) {
			if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
				if (encodings[fnum] != 0 ||
				    ((int)ucs >= ranges[fnum * 2] &&
				     (int)ucs <= ranges[fnum * 2 + 1])) {
					break;
				}
			}
			fnum++;
		}
		if (fnum == nb_font) {
			/* the char is not valid in all encodings ->
			 * draw it using the first font :-(
			 */
			fnum = first;
			ucs2fontmap(glyph, '?', encodings[fnum]);
		}

		if (last_fnum != fnum || no_spc) {
			XSetFont(display, gc, fonts[last_fnum]->fid);
			XDrawString16(display, d, gc, x, y, buf, i);
			x += XTextWidth16(fonts[last_fnum], buf, i);
			i = 0;
			(*buf).byte1 = glyph[0];
			(*buf).byte2 = glyph[1];
			if (no_spc) {
				x -= XTextWidth16(fonts[fnum], buf, 1);
			}
		} else {
			(*(buf + i)).byte1 = glyph[0];
			(*(buf + i)).byte2 = glyph[1];
		}
		last_fnum = fnum;
		i++;
		string += ulen;
		num_bytes -= ulen;
	}

	XSetFont(display, gc, fonts[fnum]->fid);
	XDrawString16(display, d, gc, x, y, buf, i);
}


/*****************************************************************************/
/** Measure the inked extents of a UTF-8 string using multiple fonts as     **/
/** needed. Tries to mirror the behaviour of the draw function              **/
/** XUtf8DrawString() as closely as possible to get consistent sizes.       **/
/*****************************************************************************/
void
XUtf8_measure_extents(
        Display         	*display,
        Drawable        	d,
        XUtf8FontStruct  *font_set,
        GC              	gc,
        int             	*xx,     /* x-offset from origin */
        int             	*yy,     /* y-offset from origin */
        int             	*ww,     /* overall inked width  */
        int             	*hh,     /* maximum inked height */
        const char      	*string, /* text to measure */
        int             	num_bytes)
{
	int 		*encodings; /* encodings array */
	XFontStruct 	**fonts;    /* fonts array */
	Fl_XChar2b 	buf[128];   /* drawing buffer */
	int 		fnum;       /* index of the current font in the fonts array*/
	int 		i;          /* current byte in the XChar2b buffer */
	int 		first;      /* first valid font index */
	int 		last_fnum;  /* font index of the previous char */
	int 		nb_font;    /* quantity of fonts in the font array */
	char 		glyph[2];   /* byte1 and byte2 value of the UTF-8 char */
	int		*ranges;    /* sub range of iso10646 */

	int wd = 0; /* accumulates the width of the text */
	int ht = 0; /* used to find max height in text */
	int hs;     /* "height sum" of current text segment */
	int yt = 0x7FFFFFFF; /* used to find bounding rectangle delta-y */
	/* int res; */ /* result from calling XTextExtents16() - we should test this is OK! */
	/* FC: the man does not specify error codes for it, but X will generate X errors like BadGC or BadFont. */

	XCharStruct sizes;
	int dir_ret = 0;
	int fnt_asc = 0;
	int fnt_dsc = 0;

	nb_font = font_set->nb_font;

	if (nb_font < 1) {
		/* there is no font in the font_set :-( */
		return;
	}
	ranges = font_set->ranges;
	fonts = font_set->fonts;
	encodings = font_set->encodings;
	i = 0;
	fnum = 0;

	while(fnum < nb_font && !fonts[fnum]) fnum++;
	if (fnum >= nb_font) {
		/* there is no valid font for the X server */
		return;
	}

	first = fnum;
	last_fnum = fnum;

	while (num_bytes > 0) {
		int 	 ulen;   /* byte length of the UTF-8 char */
		unsigned int ucs;    /* Unicode value of the UTF-8 char */
		unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */

		if (i > 120) {
			/*** draw the buffer **/
			XSetFont(display, gc, fonts[fnum]->fid);
			/* res = */
			XTextExtents16(fonts[fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes);
			/* recover the dimensions - should verify that res == 0 first! */
			wd += sizes.width; /* accumulate the width */
			hs = sizes.ascent + sizes.descent; /* total height */
			if(hs > ht) ht = hs; /* new height exceeds previous height */
			if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */
			i = 0;
		}

		ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs);

		if (ulen < 1) ulen = 1;

		no_spc = XUtf8IsNonSpacing(ucs);
		if (no_spc) ucs = no_spc;

		/*
		 * find the first encoding which can be used to
		 * draw the glyph
		 */
		fnum = first;
		while (fnum < nb_font) {
			if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
				if (encodings[fnum] != 0 ||
				    ((int)ucs >= ranges[fnum * 2] &&
				     (int)ucs <= ranges[fnum * 2 + 1])) {
					break;
				}
			}
			fnum++;
		}
		if (fnum == nb_font) {
			/* the char is not valid in all encodings ->
			 * draw it using the first font :-(
			 */
			fnum = first;
			ucs2fontmap(glyph, '?', encodings[fnum]);
		}

		if (last_fnum != fnum || no_spc) {
			XSetFont(display, gc, fonts[last_fnum]->fid);
			/* res = */
			XTextExtents16(fonts[last_fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes);
			/* recover the dimensions - should verify that res == 0 first! */
			wd += sizes.width; /* accumulate the width */
			hs = sizes.ascent + sizes.descent; /* total height */
			if(hs > ht) ht = hs; /* new height exceeds previous height */
			if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */
			i = 0;
			(*buf).byte1 = glyph[0];
			(*buf).byte2 = glyph[1];
			if (no_spc) {
				wd -= XTextWidth16(fonts[fnum], buf, 1);
			}
		} else {
			(*(buf + i)).byte1 = glyph[0];
			(*(buf + i)).byte2 = glyph[1];
		}
		last_fnum = fnum;
		i++;
		string += ulen;
		num_bytes -= ulen;
	}

	XSetFont(display, gc, fonts[fnum]->fid);
	/* res = */
	XTextExtents16(fonts[fnum], buf, i, &dir_ret, &fnt_asc, &fnt_dsc, &sizes);
	/* recover the dimensions - should verify that res == 0 first! */
	wd += sizes.width; /* accumulate the width */
	hs = sizes.ascent + sizes.descent; /* total height */
	if(hs > ht) ht = hs; /* new height exceeds previous height */
	if(yt > (-sizes.ascent)) yt = -sizes.ascent; /* delta y offset */
	/* return values */
	*ww = wd; /* width of inked area rectangle */
	*hh = ht; /* max height of inked area rectangle */
	*xx = 0;  /* x-offset from origin to start of inked area - this is wrong! */
	*yy = yt; /* y-offset from origin to start of inked rectangle */
}


/*****************************************************************************/
/** returns the pixel width of a UTF-8 string				    **/
/*****************************************************************************/
int
XUtf8TextWidth(XUtf8FontStruct 	*font_set,
               const char 	*string,
               int 		num_bytes)
{

	int		x;
	int 		*encodings; /* encodings array */
	XFontStruct 	**fonts;    /* fonts array */
	Fl_XChar2b 	buf[128];   /* drawing buffer */
	int 		fnum;       /* index of the current font in the fonts array*/
	int 		i;          /* current byte in the XChar2b buffer */
	int 		first;      /* first valid font index */
	int 		last_fnum;  /* font index of the previous char */
	int 		nb_font;    /* quantity of fonts in the font array */
	char 		glyph[2];   /* byte1 and byte2 value of the UTF-8 char */
	int		*ranges;    /* sub range of iso10646 */

	nb_font = font_set->nb_font;
	x = 0;

	if (nb_font < 1) {
		/* there is no font in the font_set :-( */
		return x;
	}

	ranges = font_set->ranges;
	fonts = font_set->fonts;
	encodings = font_set->encodings;
	i = 0;
	fnum = 0;

	while(fnum < nb_font && !fonts[fnum]) fnum++;
	if (fnum >= nb_font) {
		/* there is no valid font for the X server */
		return x;
	}

	first = fnum;
	last_fnum = fnum;

	while (num_bytes > 0) {
		int 	 ulen;   /* byte length of the UTF-8 char */
		unsigned int ucs;    /* Unicode value of the UTF-8 char */
		unsigned int no_spc; /* Spacing char equivalent of a non-spacing char */

		if (i > 120) {
			/*** measure the buffer **/
			x += XTextWidth16(fonts[fnum], buf, i);
			i = 0;
		}

		ulen = XFastConvertUtf8ToUcs((unsigned char*)string, num_bytes, &ucs);

		if (ulen < 1) ulen = 1;

		no_spc = XUtf8IsNonSpacing(ucs);
		if (no_spc) {
			ucs = no_spc;
		}

		/*
		 * find the first encoding which can be used to
		 * draw the glyph
		 */
		fnum = first;
		while (fnum < nb_font) {
			if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
				if (encodings[fnum] != 0 ||
				    ((int)ucs >= ranges[fnum * 2] &&
				     (int)ucs <= ranges[fnum * 2 + 1])) {
					break;
				}
			}
			fnum++;
		}
		if (fnum == nb_font) {
			/* the char is not valid in all encodings ->
			 * draw it using the first font :-(
			 */
			fnum = first;
			ucs2fontmap(glyph, '?', encodings[fnum]);
		}

		if (last_fnum != fnum || no_spc) {
			x += XTextWidth16(fonts[last_fnum], buf, i);
			i = 0;
			(*buf).byte1 = glyph[0];
			(*buf).byte2 = glyph[1];
			if (no_spc) {
				/* go back to draw the non-spacing char over the previous char */
				x -= XTextWidth16(fonts[fnum], buf, 1);
			}
		} else {
			(*(buf + i)).byte1 = glyph[0];
			(*(buf + i)).byte2 = glyph[1];
		}
		last_fnum = fnum;
		i++;
		string += ulen;
		num_bytes -= ulen;
	}

	x += XTextWidth16(fonts[last_fnum], buf, i);

	return x;
}

/*****************************************************************************/
/**  get the X font and glyph ID of a UCS char                              **/
/*****************************************************************************/
int
fl_XGetUtf8FontAndGlyph(XUtf8FontStruct  *font_set,
                        unsigned int     ucs,
                        XFontStruct      **fnt,
                        unsigned short   *id)
{

	int             *encodings; /* encodings array */
	XFontStruct     **fonts;    /* fonts array */
	int             fnum;       /* index of the current font in the fonts array*/
	int             first;      /* first valid font index */
	int             nb_font;    /* quantity of fonts in the font array */
	char 		  glyph[2];   /* byte1 and byte2 value of the UTF-8 char */
	int             *ranges;    /* sub range of iso10646 */

	nb_font = font_set->nb_font;

	if (nb_font < 1) {
		/* there is no font in the font_set :-( */
		return -1;
	}

	ranges = font_set->ranges;
	fonts = font_set->fonts;
	encodings = font_set->encodings;
	fnum = 0;

	while(fnum < nb_font && !fonts[fnum]) fnum++;
	if (fnum >= nb_font) {
		/* there is no valid font for the X server */
		return -1;
	}

	first = fnum;

	/*
	 * find the first encoding which can be used to draw the glyph
	 */
	fnum = first;
	while (fnum < nb_font) {
		if (fonts[fnum] && ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
			if (encodings[fnum] != 0 ||
			    ((int)ucs >= ranges[fnum * 2] &&
			     (int)ucs <= ranges[fnum * 2 + 1])) {
				break;
			}
		}
		fnum++;
	}
	if (fnum == nb_font) {
		/* the char is not valid in all encodings ->
		 * draw it using the first font :-(
		 */
		fnum = first;
		ucs2fontmap(glyph, '?', encodings[fnum]);
	}

	*id = ((unsigned char)glyph[0] << 8) | (unsigned char)glyph[1] ;
	*fnt = fonts[fnum];
	return 0;
}

/*****************************************************************************/
/** returns the pixel width of a UCS char				    **/
/*****************************************************************************/
int
XUtf8UcsWidth(XUtf8FontStruct  *font_set,
              unsigned int     ucs)
{

	int		x;
	int 		*encodings; /* encodings array */
	XFontStruct 	**fonts;    /* fonts array */
	Fl_XChar2b 	buf[8];     /* drawing buffer */
	int 		fnum;       /* index of the current font in the fonts array*/
	int 		first;      /* first valid font index */
	int 		nb_font;    /* quantity of fonts in the font array */
	char 		glyph[2];   /* byte1 and byte2 value of the UTF-8 char */
	int		*ranges;    /* sub range of iso10646 */
	unsigned int  no_spc;

	nb_font = font_set->nb_font;
	x = 0;

	if (nb_font < 1) {
		/* there is no font in the font_set :-( */
		return x;
	}

	ranges = font_set->ranges;
	fonts = font_set->fonts;
	encodings = font_set->encodings;
	fnum = 0;

	while(fnum < nb_font && !fonts[fnum]) fnum++;
	if (fnum >= nb_font) {
		/* there is no valid font for the X server */
		return x;
	}

	first = fnum;

	no_spc = XUtf8IsNonSpacing(ucs);
	if (no_spc) ucs = no_spc;

	/*
	 * find the first encoding which can be used to
	 * draw the glyph
	 */
	fnum = first;
	while (fnum < nb_font) {
		if (fonts[fnum] &&
		    ucs2fontmap(glyph, ucs, encodings[fnum]) >= 0) {
			if (encodings[fnum] != 0 || ((int)ucs >= ranges[fnum * 2] &&
			                             (int)ucs <= ranges[fnum * 2 + 1])) {
				break;
			}
		}
		fnum++;
	}
	if (fnum == nb_font) {
		/* the char is not valid in all encodings ->
		 * draw it using the first font :-(
		 */
		fnum = first;
		ucs2fontmap(glyph, '?', encodings[fnum]);
	}

	(*buf).byte1 = glyph[0];
	(*buf).byte2 = glyph[1];

	x += XTextWidth16(fonts[fnum], buf, 1);

	return x;
}

/*****************************************************************************/
/** draw an UTF-8 string and clear the background.	 		    **/
/*****************************************************************************/
void
XUtf8DrawImageString(Display         *display,
                     Drawable        d,
                     XUtf8FontStruct *font_set,
                     GC              gc,
                     int             x,
                     int             y,
                     const char      *string,
                     int             num_bytes)
{

	/* FIXME: must be improved ! */
	int w;
	int fill_style;
	unsigned long foreground;
	unsigned long background;
	int function;
	XGCValues xgcv;

	w = XUtf8TextWidth(font_set, string, num_bytes);

	XGetGCValues(display, gc,
	             GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);

	function = xgcv.function;
	fill_style = xgcv.fill_style;
	foreground = xgcv.foreground;
	background = xgcv.background;

	xgcv.function = GXcopy;
	xgcv.foreground = background;
	xgcv.background = foreground;
	xgcv.fill_style = FillSolid;

	XChangeGC(display, gc,
	          GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);

	XFillRectangle(display, d, gc, x, y - font_set->ascent,
	               (unsigned)w, (unsigned)(font_set->ascent + font_set->descent));

	xgcv.function = function;
	xgcv.foreground = foreground;
	xgcv.background = background;
	xgcv.fill_style = fill_style;

	XChangeGC(display, gc,
	          GCFunction|GCForeground|GCBackground|GCFillStyle, &xgcv);

	XUtf8DrawString(display, d, font_set, gc, x, y, string, num_bytes);
}

/*****************************************************************************/
/** free the XFontSet and others things created by XCreateUtf8FontSet       **/
/*****************************************************************************/
void
XFreeUtf8FontStruct(Display 	    *dpy,
                    XUtf8FontStruct *font_set)
{

	int i;
	i = 0;
	while (i < font_set->nb_font) {
		if (font_set->fonts[i]) {
			XFreeFont(dpy, font_set->fonts[i]);
			free(font_set->font_name_list[i]);
		}
		i++;
	}
	free(font_set->ranges);
	free(font_set->font_name_list);
	free(font_set->fonts);
	free(font_set->encodings);
	free(font_set);
}

#endif

#endif /* X11 only */

/*
 *  End of "$Id: utf8Wrap.c 9994 2013-09-25 21:09:00Z greg.ercolano $".
 */
